﻿using Abp.Domain.Repositories;
using Abp.Domain.Services;
using Abp.UI;
using AmuTools.Normal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace shenghua.Common.WordNodes
{
    public class WordNodeManager<T>: DomainService
        where T:WordNode, new()
    {
        protected readonly IRepository<T> _repository;

        protected bool Sortable { get; set; }

        public WordNodeManager(
            IRepository<T> repository)
        {
            _repository = repository;
            Sortable = true;
        }

        public virtual Task<T> Add(int? parentId, string name, string tag = null)
        {
            T word = new T
            {
                ParentId = parentId,
                Name = name,
                Tag = tag
            };
            return Add(word);
        }

        public virtual async Task<T> Add(T word)
        {
            if(word.Name == null)
            {
                word.Name = HashHelper.RandomHash_32();
            }
            int count = _repository.GetAll().Where(r => r.Name == word.Name).Count();
            if (count > 0)
            {
                throw new UserFriendlyException($"{typeof(T).FullName}唯一名称重复");
            }

            if(word.ParentId != null)
            {
                CheckWord((int)word.ParentId);
            }

            if (Sortable)
            {
                word.Sort = await Count(word.ParentId) + 1;
            }
            await _repository.InsertAndGetIdAsync(word);
            return word;
        }

        public virtual async Task SortUp(int wordId)
        {
            CheckSortable("SortUp");

            T current = await Get(wordId);
            T prev = _repository.GetAll().Where(r => r.ParentId == current.ParentId && r.Sort == current.Sort - 1).FirstOrDefault();

            if (prev == null) return;

            current.Sort -= 1;
            prev.Sort += 1;
            await Update(current);
            await Update(prev);
        }

        public virtual async Task SortDown(int wordId)
        {
            CheckSortable("SortDown");

            T current = await Get(wordId);
            T next = _repository.GetAll().Where(r => r.ParentId == current.ParentId && r.Sort == current.Sort + 1).FirstOrDefault();

            if (next == null) return;

            current.Sort += 1;
            next.Sort -= 1;
            await Update(current);
            await Update(next);
        }

        public virtual async Task MoveTo(int wordId, int? parentId)
        {
            if(wordId == parentId)
            {
                throw new UserFriendlyException("节点ID一致，不能指向自身");
            }

            T current = await Get(wordId);
            if(current.Id == parentId)
            {
                throw new UserFriendlyException("节点已经在指定父节点下");
            }
            
            int? tempParentId = parentId;
            while (tempParentId != null)
            {
                T parent = await Get((int)tempParentId);
                if (parent.ParentId == wordId)
                {
                    throw new UserFriendlyException("不能将节点作为子节点的子节点");
                }
                tempParentId = parent.ParentId;
            }

            // 先从当前父节点排除出去
            await ResetSortWithoutOne(wordId, current.ParentId);

            // 指定到新的父节点
            current.ParentId = parentId;
            if(Sortable)
            {
                current.Sort = await Count(parentId) + 1;
            }
            await Update(current);

        }

        /// <summary>
        /// 移动到上一级
        /// </summary>
        /// <param name="wordId"></param>
        /// <returns></returns>
        public virtual async Task MoveUp(int wordId)
        {
            T word = await Get(wordId);
            if(word.ParentId == null)
            {
                throw new UserFriendlyException("已经在根级别下了，没有更高级别目录");
            }
            var parent = await Get((int)word.ParentId);
            await MoveTo(wordId, parent.ParentId);
        }

        /// <summary>
        /// 移动到下一级,默认为移动到上一个兄弟节点下
        /// </summary>
        /// <param name="wordId"></param>
        /// <returns></returns>
        public virtual async Task MoveDown(int wordId)
        {
            CheckSortable("MoveDown");

            T word = await Get(wordId);
            if(word.Sort == 1)
            {
                throw new UserFriendlyException("节点前面没有兄弟节点。移动到下一级操作会将该节点移动到上一个兄弟节点下");
            }
            T parent = _repository.GetAll().Where(r => r.ParentId == word.ParentId && r.Sort == word.Sort - 1).FirstOrDefault();
            await MoveTo(wordId, parent.Id);
        }

        public virtual async Task Enabled(int wordId, bool value)
        {
            T word = _repository.Get(wordId);
            word.Enabled = value;
            await _repository.UpdateAsync(word);
        }

        public virtual async Task SetDefault(int wordId)
        {
            T word = await Get(wordId);
            List<T> oldDefault = await _repository.GetAllListAsync(r => r.ParentId == word.ParentId && r.IsDefault);
            foreach(var item in oldDefault)
            {
                if (item.Id == wordId) return;
                item.IsDefault = false;
                await Update(item);
            }
            word.IsDefault = true;
            await Update(word);
        }

        public virtual async Task OnlyMemberVisible(int wordId, bool value)
        {
            T word = _repository.Get(wordId);
            word.OnlyMemberVisible = value;
            await _repository.UpdateAsync(word);
        }

        public virtual async Task<T> Update(int wordId, string name)
        {
            T word = _repository.Get(wordId);
            word.Name = name;
            return await _repository.UpdateAsync(word);
        }

        public virtual async Task<T> Update(T word)
        {
            return await _repository.UpdateAsync(word);
        }

        public virtual async Task Delete(int wordId)
        {
            await Delete(wordId, false);
        }

        public virtual async Task Delete(int wordId, bool force)
        {
            T word = await Get(wordId);
            if(word.IsStatic)
            {
                throw new UserFriendlyException("当前节点为静态节点，不可删除");
            }
            if(force)
            {
                // 强制删除
                await DeleteChildren(wordId);
            }
            else
            {
                // 不允许强制删除，则同样不允许有子节点
                if(await Count(wordId) > 0)
                {
                    throw new UserFriendlyException("节点存在子节点，不能删除");
                }
            }
            // 删除自身
            await ResetSortWithoutOne(word.Id, word.ParentId);
            await _repository.DeleteAsync(word.Id);
        }

        public virtual async Task DeleteChildren(int? parentId)
        {
            List<T> words = await GetAll(parentId);
            foreach(var item in words)
            {
                await DeleteChildren(item.Id);
                await _repository.DeleteAsync(item.Id);
            }
        }

        public virtual async Task<T> Get(int id)
        {
            var item = await _repository.GetAsync(id);
            if(item == null)
            {
                throw new UserFriendlyException("请求的节点不存在");
            }
            return item;
        }

        public virtual async Task<List<T>> GetAll(int? parentId = null)
        {
            var query = _repository.GetAll().Where(r => r.ParentId == parentId);
            if(Sortable)
            {
                query = query.OrderBy(r => r.Sort);
            }
            return query.ToList();
        }

        public virtual async Task<int> Count(int? parentId = null)
        {
            return _repository.GetAll().Where(r => r.ParentId == parentId).Count();
        }

        private async Task ResetSortWithoutOne(int wordId, int? parentId)
        {
            if (!Sortable) return;

            List<T> words = _repository.GetAll().Where(r => r.Id != wordId && r.ParentId == parentId).OrderBy(r => r.Sort).ToList();
            for (int i = 0; i < words.Count; i++)
            {
                words[i].Sort = i + 1;
                await Update(words[i]);
            }
        }

        public virtual async Task<List<WordTree<T>>> GetTree(int? parentId = null)
        {
            List<WordTree<T>> children = new List<WordTree<T>>();
            List<T> words = await GetAll(parentId);
            foreach(var word in words)
            {
                children.Add(new WordTree<T>
                {
                    Value = word,
                    Children = await GetTree(word.Id)
                });
            }
            return children;
        }

        private void CheckSortable(string funcName)
        {
            if(!Sortable)
            {
                throw new UserFriendlyException($"未开启排序，函数{funcName}不可用");
            }
        }

        private void CheckWord(int wordId)
        {
            Get(wordId).Wait();
        }
    }
}
